#ifndef __HTTP_HPP__
#define __HTTP_HPP__

#include "../src/server.hpp"
#include "util.hpp"
#include <regex>

class HttpRequest
{
public:
    std::string _method;                                    // 请求方法
    std::string _path;                                      // 资源路径
    std::unordered_map<std::string, std::string> _params;   // 查询字符串
    std::string _version;                                   // http版本
    std::unordered_map<std::string, std::string> _headers;  // 请求头部
    std::string _body;                                      // 请求正文
    std::smatch _matches;                                   // 保存正则解析首行得到的数据
public:
    /* 添加/设置头部字段 */
    void SetHeader(const std::string& key, const std::string& val)
    {
        _headers.insert(std::make_pair(key, val));
    }
    /* 判断是否有某个头部字段 */
    bool HasHeader(const std::string& key) const
    {
        return _headers.count(key) != 0;
    }
    /* 根据键值取出某个头部字段的值 */
    std::string GetHeader(const std::string& key) const
    {
        auto it = _headers.find(key);
        if(it == _headers.end()) return "";
        return it->second;
    }
    /* 添加/设置查询字符串 */
    void SetParam(const std::string& key, const std::string& val)
    {
        _params.insert(std::make_pair(key, val));
    }
    /* 判断是否有某个指定的查询字符串 */
    bool HasParam(const std::string& key) const
    {
        return _params.count(key) != 0;
    }
    /* 根据键值获取查询字符串 */
    std::string GetParam(const std::string& key) const
    {
        auto it = _params.find(key);
        if(it == _params.end()) return "";
        return it->second;
    }
    /* 获取正文长度 */
    size_t ContentLength() const
    {
        if(HasHeader("Content-length") == false) return 0;
        return std::stoul(GetHeader("Content-length"));
    }
    /* 本次通信结束是否关闭连接——即是否是短连接 */
    bool ToClose() const
    {
        if(HasHeader("Connection") == false) return false;
        if(GetHeader("Connection") == "close") return false;
        return true;// Connection: keep-alive
    }

    /* 重置http请求 */
    void Reset()
    {
        _method.clear();
        _path.clear();
        _params.clear();
        _version.clear();
        _headers.clear();
        _body.clear();
        std::smatch matches;
        _matches.swap(matches);
    }
};

class HttpResponse
{
public:
    int _status;// 响应状态码
    std::unordered_map<std::string, std::string> _headers;// 响应头部
    std::string _body;// 响应正文
    bool _redirect_flag;// 重定向标志 是否重定向
    std::string _redirect_url;// 重定向路径
public:
    HttpResponse(): _status(200), _redirect_flag(false)// 响应状态码默认200
    {}
    HttpResponse(int status): _status(status), _redirect_flag(true)
    {}
public:
    /* 添加/设置头部字段 */
    void SetHeader(const std::string& key, const std::string& val)
    {
        _headers.insert(std::make_pair(key, val));
    }
    /* 判断是否有某个头部字段 */
    bool HasHeader(const std::string& key) const
    {
        return _headers.count(key) != 0;
    }
    /* 根据键值取出某个头部字段的值 */
    std::string GetHeader(const std::string& key) const
    {
        auto it = _headers.find(key);
        if(it == _headers.end()) return "";
        return it->second;
    }
    /* 设置正文 和 响应文件类型 */
    void SetContent(const std::string& body, const std::string& type = "text/html")
    {
        _body = body;
        SetHeader("Content-Type", type);// 默认是html页面
    }
    /* 设置重定向信息 */
    void SetRedirect(const std::string& url, const int status = 302)
    {
        _status = status;
        _redirect_flag = true;
        _redirect_url = url;
    }
    /* 本次通信结束是否关闭连接 */
    bool ToClose() const
    {
        if(HasHeader("Connection") == true && GetHeader("Connection") == "keep-alive") return true;
        return false;
    }

    /* 重置http响应 */
    void Reset()
    {
        _status = 200;
        _headers.clear();
        _body.clear();
        _redirect_flag = false;
        _redirect_url.clear();
    }
};


/* 上下文状态 */
typedef enum
{
    RECV_HTTP_ERROR,// 接收处理失败
    RECV_HTTP_LINE,// 正在接收处理请求行
    RECV_HTTP_HEAD,// 正在接收处理请求头部
    RECV_HTTP_BODY,// 正在接收处理请求正文
    RECV_HTTP_OVER// 接收处理完成
}HttpRecvStatus;

class HttpContext
{
private:
    HttpRecvStatus _recv_status;// 当前接收解析请求的状态 表明处于哪个阶段
    int _resp_status;// 响应状态码
    HttpRequest _request;// 解析完成得到的信息
private:
    /* 接收请求行 */
    bool RecvHttpLine();
    /* 解析请求行 */
    bool ParseHttpLine();
    /* 接收请求头部 */
    bool RecvHttpHead();
    /* 解析请求头部 */
    bool ParseHttpHead();
    /* 接收请求正文 */
    bool RecvHttpContent();
public:
    HttpContext(): _resp_status(200), _recv_status(RECV_HTTP_LINE)
    {}
public:
    /* 获取接收解析状态 */
    HttpRecvStatus RecvStatus() const;
    /* 获取响应状态码 */
    int RespStatus() const;
    /* 获取解析得到的信息 */
    HttpRequest& Request() const;

    /* 接收并解析http请求 */
    void RecvHttpRequest();
};

#endif